/**
 * 
 */
package info.niwota.webime.http;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.BindException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.SSLSocket;

/**
 * @author qiangli
 * 
 */
public class HttpsConnector implements Connector, Lifecycle, Runnable {
	private static final String PROTOCOL = "https";

	private static final String KEYSTORE = "/info/niwota/localweb/keystore/keystore.bks";

	private static final String TAG = "HttpsConnector";

	private static final int ANY_PORT = 0;

	private int instanceId = 0;

	private final String host = "localhost";

	private int sport = ANY_PORT;

	private PI pi;

	private SSLServerSocket ss;

	private Thread th;

	private ServerContext ctx;

	/** 
	 */
	public HttpsConnector() {
	}

	public void setPI(PI pi) {
		this.pi = pi;
	}
	
	public String getHost() {
		return host;
	}

	public int getPort() {
		return sport;
	}

	public void run() {

		URI base = null;
		try {
			base = new URL(PROTOCOL, host, sport, "/").toURI();
		} catch (MalformedURLException e1) {
			e1.printStackTrace();
		} catch (URISyntaxException e1) {
			e1.printStackTrace();
		}
		while (ss != null) {
			try {
				if (Debug.DEBUG) {
					Log.d(TAG, "HTTPS Connector [" + host + ":" + sport + " "
							+ (++instanceId) + "]");
				}
				
				SSLSocket s = (SSLSocket) ss.accept();
				if (pi != null) {
					WebContext wc = new WebContext(PROTOCOL);
					wc.serverContext = ctx;
					wc.baseUri = base;

					pi.service(wc, s);
				} else {
					if (Debug.DEBUG) {
						Log.d(TAG, "No PI set.");
					}
				}
			} catch (Exception e) {
				// e.printStackTrace();
			}
		}
	}

	public void shutdown() {
		if (Debug.DEBUG) {
			Log.d(TAG, "HTTPS Connector stopping...");
		}
		try {
			//close hangs, so we try our best
			Thread t = new Thread() {
				public void run() {
					try {
						ss.close();
						ss = null;
						ctx = null;
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			};
			t.start();
		} catch (Exception e) {
			e.printStackTrace();
		}
		th.interrupt();
		//
		if (Debug.DEBUG) {
			Log.d(TAG, "HTTPS Connector stopped");
		}
	}

	private InputStream getKeystore(String file) throws FileNotFoundException {
		if (file == null) {
			return getClass().getResourceAsStream(KEYSTORE);
		}
		// /sdcard/hotweb/etc/keystore.bks
		return new FileInputStream(file);
	}

	public void startup() {
		if (Debug.DEBUG) {
			Log.d(TAG, "HTTPS Connector starting...");
		}
		try {
			String keystore = null; // get custom keystore filename
			char kspass[] = "hotweb".toCharArray();
			char ctpass[] = "hotweb".toCharArray();
			KeyStore ks = KeyStore.getInstance("BKS");
			InputStream is = getKeystore(keystore);
			ks.load(is, kspass);
			String alg = KeyManagerFactory.getDefaultAlgorithm();
			if (Debug.DEBUG) {
				Log.d(TAG, "startup alg=" + alg + " keystore: " + keystore);
			}
			KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
			kmf.init(ks, ctpass);
			SSLContext sc = SSLContext.getInstance("TLS");
			sc.init(kmf.getKeyManagers(), null, null);
			SSLServerSocketFactory ssf = sc.getServerSocketFactory();
			ss = (SSLServerSocket) ssf.createServerSocket(sport);
			
			if (sport == ANY_PORT) {
				sport = ss.getLocalPort();
			}
			//
			is.close();
		} catch (BindException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}
		//
		th = new Thread(this);
		th.setDaemon(true);
		th.start();
		//
		if (Debug.DEBUG) {
			Log.d(TAG, "HTTPS Connector started");
		}
	}

	public void init(ServerContext ctx) {
		this.ctx = ctx;
		sport = 443;
	}
}
